home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / Main.bin / PixelGrabber.java < prev    next >
Text File  |  1998-09-22  |  18KB  |  567 lines

  1. /*
  2.  * @(#)PixelGrabber.java    1.8 98/07/01
  3.  *
  4.  * Copyright 1995-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  * 
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.awt.image;
  16.  
  17. import java.util.Hashtable;
  18. import java.awt.image.ImageProducer;
  19. import java.awt.image.ImageConsumer;
  20. import java.awt.image.ColorModel;
  21. import java.awt.Image;
  22.  
  23. /**
  24.  * The PixelGrabber class implements an ImageConsumer which can be attached
  25.  * to an Image or ImageProducer object to retrieve a subset of the pixels
  26.  * in that image.  Here is an example:
  27.  * <pre>
  28.  *
  29.  * public void handlesinglepixel(int x, int y, int pixel) {
  30.  *    int alpha = (pixel >> 24) & 0xff;
  31.  *    int red   = (pixel >> 16) & 0xff;
  32.  *    int green = (pixel >>  8) & 0xff;
  33.  *    int blue  = (pixel      ) & 0xff;
  34.  *    // Deal with the pixel as necessary...
  35.  * }
  36.  *
  37.  * public void handlepixels(Image img, int x, int y, int w, int h) {
  38.  *    int[] pixels = new int[w * h];
  39.  *    PixelGrabber pg = new PixelGrabber(img, x, y, w, h, pixels, 0, w);
  40.  *    try {
  41.  *        pg.grabPixels();
  42.  *    } catch (InterruptedException e) {
  43.  *        System.err.println("interrupted waiting for pixels!");
  44.  *        return;
  45.  *    }
  46.  *    if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
  47.  *        System.err.println("image fetch aborted or errored");
  48.  *        return;
  49.  *    }
  50.  *    for (int j = 0; j < h; j++) {
  51.  *        for (int i = 0; i < w; i++) {
  52.  *        handlesinglepixel(x+i, y+j, pixels[j * w + i]);
  53.  *        }
  54.  *    }
  55.  * }
  56.  *
  57.  * </pre>
  58.  *
  59.  * @see ColorModel#getRGBdefault
  60.  *
  61.  * @version     1.8, 07/01/98
  62.  * @author     Jim Graham
  63.  */
  64. public class PixelGrabber implements ImageConsumer {
  65.     ImageProducer producer;
  66.  
  67.     int dstX;
  68.     int dstY;
  69.     int dstW;
  70.     int dstH;
  71.  
  72.     ColorModel imageModel;
  73.     byte[] bytePixels;
  74.     int[] intPixels;
  75.     int dstOff;
  76.     int dstScan;
  77.  
  78.     private boolean grabbing;
  79.     private int flags;
  80.  
  81.     private final int GRABBEDBITS = (ImageObserver.FRAMEBITS
  82.                      | ImageObserver.ALLBITS);
  83.     private final int DONEBITS = (GRABBEDBITS
  84.                   | ImageObserver.ERROR);
  85.  
  86.     /**
  87.      * Create a PixelGrabber object to grab the (x, y, w, h) rectangular
  88.      * section of pixels from the specified image into the given array.
  89.      * The pixels are stored into the array in the default RGB ColorModel.
  90.      * The RGB data for pixel (i, j) where (i, j) is inside the rectangle
  91.      * (x, y, w, h) is stored in the array at
  92.      * <tt>pix[(j - y) * scansize + (i - x) + off]</tt>.
  93.      * @see ColorModel#getRGBdefault
  94.      * @param img the image to retrieve pixels from
  95.      * @param x the x coordinate of the upper left corner of the rectangle
  96.      * of pixels to retrieve from the image, relative to the default
  97.      * (unscaled) size of the image
  98.      * @param y the y coordinate of the upper left corner of the rectangle
  99.      * of pixels to retrieve from the image
  100.      * @param w the width of the rectangle of pixels to retrieve
  101.      * @param h the height of the rectangle of pixels to retrieve
  102.      * @param pix the array of integers which are to be used to hold the
  103.      * RGB pixels retrieved from the image
  104.      * @param off the offset into the array of where to store the first pixel
  105.      * @param scansize the distance from one row of pixels to the next in
  106.      * the array
  107.      */
  108.     public PixelGrabber(Image img, int x, int y, int w, int h,
  109.             int[] pix, int off, int scansize) {
  110.     this(img.getSource(), x, y, w, h, pix, off, scansize);
  111.     }
  112.  
  113.     /**
  114.      * Create a PixelGrabber object to grab the (x, y, w, h) rectangular
  115.      * section of pixels from the image produced by the specified
  116.      * ImageProducer into the given array.
  117.      * The pixels are stored into the array in the default RGB ColorModel.
  118.      * The RGB data for pixel (i, j) where (i, j) is inside the rectangle
  119.      * (x, y, w, h) is stored in the array at
  120.      * <tt>pix[(j - y) * scansize + (i - x) + off]</tt>.
  121.      * @see ColorModel#getRGBdefault
  122.      * @param img the image to retrieve pixels from
  123.      * @param x the x coordinate of the upper left corner of the rectangle
  124.      * of pixels to retrieve from the image, relative to the default
  125.      * (unscaled) size of the image
  126.      * @param y the y coordinate of the upper left corner of the rectangle
  127.      * of pixels to retrieve from the image
  128.      * @param w the width of the rectangle of pixels to retrieve
  129.      * @param h the height of the rectangle of pixels to retrieve
  130.      * @param pix the array of integers which are to be used to hold the
  131.      * RGB pixels retrieved from the image
  132.      * @param off the offset into the array of where to store the first pixel
  133.      * @param scansize the distance from one row of pixels to the next in
  134.      * the array
  135.      */
  136.     public PixelGrabber(ImageProducer ip, int x, int y, int w, int h,
  137.             int[] pix, int off, int scansize) {
  138.     producer = ip;
  139.     dstX = x;
  140.     dstY = y;
  141.     dstW = w;
  142.     dstH = h;
  143.     dstOff = off;
  144.     dstScan = scansize;
  145.     intPixels = pix;
  146.     imageModel = ColorModel.getRGBdefault();
  147.     }
  148.  
  149.     /**
  150.      * Create a PixelGrabber object to grab the (x, y, w, h) rectangular
  151.      * section of pixels from the specified image.  The pixels are
  152.      * accumulated in the original ColorModel if the same ColorModel
  153.      * is used for every call to setPixels, otherwise the pixels are
  154.      * accumulated in the default RGB ColorModel.  If the forceRGB
  155.      * parameter is true, then the pixels will be accumulated in the
  156.      * default RGB ColorModel anywya.  A buffer is allocated by the
  157.      * PixelGrabber to hold the pixels in either case.  If (w < 0) or
  158.      * (h < 0), then they will default to the remaining width and
  159.      * height of the source data when that information is delivered.
  160.      * @param img the image to retrieve the image data from
  161.      * @param x the x coordinate of the upper left corner of the rectangle
  162.      * of pixels to retrieve from the image, relative to the default
  163.      * (unscaled) size of the image
  164.      * @param y the y coordinate of the upper left corner of the rectangle
  165.      * of pixels to retrieve from the image
  166.      * @param w the width of the rectangle of pixels to retrieve
  167.      * @param h the height of the rectangle of pixels to retrieve
  168.      * @param forceRGB true if the pixels should always be converted to
  169.      * the default RGB ColorModel
  170.      */
  171.     public PixelGrabber(Image img, int x, int y, int w, int h,
  172.             boolean forceRGB)
  173.     {
  174.     producer = img.getSource();
  175.     dstX = x;
  176.     dstY = y;
  177.     dstW = w;
  178.     dstH = h;
  179.     if (forceRGB) {
  180.         imageModel = ColorModel.getRGBdefault();
  181.     }
  182.     }
  183.  
  184.     /**
  185.      * Request the PixelGrabber to start fetching the pixels.
  186.      */
  187.     public synchronized void startGrabbing() {
  188.     if ((flags & DONEBITS) != 0) {
  189.         return;
  190.     }
  191.     if (!grabbing) {
  192.         grabbing = true;
  193.         flags &= ~(ImageObserver.ABORT);
  194.         producer.startProduction(this);
  195.     }
  196.     }
  197.  
  198.     /**
  199.      * Request the PixelGrabber to abort the image fetch.
  200.      */
  201.     public synchronized void abortGrabbing() {
  202.     imageComplete(IMAGEABORTED);
  203.     }
  204.  
  205.     /**
  206.      * Request the Image or ImageProducer to start delivering pixels and
  207.      * wait for all of the pixels in the rectangle of interest to be
  208.      * delivered.
  209.      * @return true if the pixels were successfully grabbed, false on
  210.      * abort, error or timeout
  211.      * @exception InterruptedException 
  212.      *            Another thread has interrupted this thread.
  213.      */
  214.     public boolean grabPixels() throws InterruptedException {
  215.     return grabPixels(0);
  216.     }
  217.  
  218.     /**
  219.      * Request the Image or ImageProducer to start delivering pixels and
  220.      * wait for all of the pixels in the rectangle of interest to be
  221.      * delivered or until the specified timeout has elapsed.
  222.      * @param ms the number of milliseconds to wait for the image pixels
  223.      * to arrive before timing out
  224.      * @return true if the pixels were successfully grabbed, false on
  225.      * abort, error or timeout
  226.      * @exception InterruptedException 
  227.      *            Another thread has interrupted this thread. 
  228.      */
  229.     public synchronized boolean grabPixels(long ms)
  230.     throws InterruptedException
  231.     {
  232.     if ((flags & DONEBITS) != 0) {
  233.         return (flags & GRABBEDBITS) != 0;
  234.     }
  235.     long end = ms + System.currentTimeMillis();
  236.     if (!grabbing) {
  237.         grabbing = true;
  238.         flags &= ~(ImageObserver.ABORT);
  239.         producer.startProduction(this);
  240.     }
  241.     while (grabbing) {
  242.         long timeout;
  243.         if (ms == 0) {
  244.         timeout = 0;
  245.         } else {
  246.         timeout = end - System.currentTimeMillis();
  247.         if (timeout <= 0) {
  248.             break;
  249.         }
  250.         }
  251.         wait(timeout);
  252.     }
  253.     return (flags & GRABBEDBITS) != 0;
  254.     }
  255.  
  256.     /**
  257.      * Return the status of the pixels.  The ImageObserver flags
  258.      * representing the available pixel information are returned.
  259.      * @see ImageObserver
  260.      * @return the bitwise OR of all relevant ImageObserver flags
  261.      */
  262.     public synchronized int getStatus() {
  263.     return flags;
  264.     }
  265.  
  266.     /**
  267.      * Get the width of the pixel buffer (after adjusting for image width).
  268.      * If no width was specified for the rectangle of pixels to grab then
  269.      * then this information will only be available after the image has
  270.      * delivered the dimensions.
  271.      * @return the final width used for the pixel buffer or -1 if the width
  272.      * is not yet known
  273.      * @see #getStatus
  274.      */
  275.     public synchronized int getWidth() {
  276.     return (dstW < 0) ? -1 : dstW;
  277.     }
  278.  
  279.     /**
  280.      * Get the height of the pixel buffer (after adjusting for image height).
  281.      * If no width was specified for the rectangle of pixels to grab then
  282.      * then this information will only be available after the image has
  283.      * delivered the dimensions.
  284.      * @return the final height used for the pixel buffer or -1 if the height
  285.      * is not yet known
  286.      * @see #getStatus
  287.      */
  288.     public synchronized int getHeight() {
  289.     return (dstH < 0) ? -1 : dstH;
  290.     }
  291.  
  292.     /**
  293.      * Get the pixel buffer.  If the PixelGrabber was not constructed
  294.      * with an explicit pixel buffer to hold the pixels then this method
  295.      * will return null until the size and format of the image data is
  296.      * known.
  297.      * Since the PixelGrabber may fall back on accumulating the data
  298.      * in the default RGB ColorModel at any time if the source image
  299.      * uses more than one ColorModel to deliver the data, the array
  300.      * object returned by this method may change over time until the
  301.      * image grab is complete.
  302.      * @return either a byte array or an int array
  303.      * @see #getStatus
  304.      */
  305.     public synchronized Object getPixels() {
  306.     return (bytePixels == null)
  307.         ? ((Object) intPixels)
  308.         : ((Object) bytePixels);
  309.     }
  310.  
  311.     /**
  312.      * Get the ColorModel for the pixels stored in the array.  If the
  313.      * PixelGrabber was constructed with an explicit pixel buffer then
  314.      * this method will always return the default RGB ColorModel,
  315.      * otherwise it may return null until the ColorModel used by the
  316.      * ImageProducer is known.
  317.      * Since the PixelGrabber may fall back on accumulating the data
  318.      * in the default RGB ColorModel at any time if the source image
  319.      * uses more than one ColorModel to deliver the data, the ColorModel
  320.      * object returned by this method may change over time until the
  321.      * image grab is complete.
  322.      * @return the ColorModel object used for storing the pixels
  323.      * @see #getStatus
  324.      * @see ColorModel#getRGBdefault
  325.      */
  326.     public synchronized ColorModel getColorModel() {
  327.     return imageModel;
  328.     }
  329.  
  330.     /**
  331.      * The setDimensions method is part of the ImageConsumer API which
  332.      * this class must implement to retrieve the pixels.
  333.      */
  334.     public void setDimensions(int width, int height) {
  335.     if (dstW < 0) {
  336.         dstW = width - dstX;
  337.     }
  338.     if (dstH < 0) {
  339.         dstH = height - dstY;
  340.     }
  341.     if (dstW <= 0 || dstH <= 0) {
  342.         imageComplete(STATICIMAGEDONE);
  343.     } else if (intPixels == null &&
  344.            imageModel == ColorModel.getRGBdefault()) {
  345.         intPixels = new int[dstW * dstH];
  346.         dstScan = dstW;
  347.         dstOff = 0;
  348.     }
  349.     flags |= (ImageObserver.WIDTH | ImageObserver.HEIGHT);
  350.     }
  351.  
  352.     /**
  353.      * The setHints method is part of the ImageConsumer API which
  354.      * this class must implement to retrieve the pixels.
  355.      */
  356.     public void setHints(int hints) {
  357.     return;
  358.     }
  359.  
  360.     /**
  361.      * The setProperties method is part of the ImageConsumer API which
  362.      * this class must implement to retrieve the pixels.
  363.      */
  364.     public void setProperties(Hashtable props) {
  365.     return;
  366.     }
  367.  
  368.     /**
  369.      * The setColorModel method is part of the ImageConsumer API which
  370.      * this class must implement to retrieve the pixels.
  371.      */
  372.     public void setColorModel(ColorModel model) {
  373.     return;
  374.     }
  375.  
  376.     private void convertToRGB() {
  377.     int size = dstW * dstH;
  378.     int newpixels[] = new int[size];
  379.     if (bytePixels != null) {
  380.         for (int i = 0; i < size; i++) {
  381.         newpixels[i] = imageModel.getRGB(bytePixels[i] & 0xff);
  382.         }
  383.     } else if (intPixels != null) {
  384.         for (int i = 0; i < size; i++) {
  385.         newpixels[i] = imageModel.getRGB(intPixels[i]);
  386.         }
  387.     }
  388.     bytePixels = null;
  389.     intPixels = newpixels;
  390.     dstScan = dstW;
  391.     dstOff = 0;
  392.     imageModel = ColorModel.getRGBdefault();
  393.     }
  394.  
  395.     /**
  396.      * The setPixels method is part of the ImageConsumer API which
  397.      * this class must implement to retrieve the pixels.
  398.      */
  399.     public void setPixels(int srcX, int srcY, int srcW, int srcH,
  400.               ColorModel model,
  401.               byte pixels[], int srcOff, int srcScan) {
  402.     if (srcY < dstY) {
  403.         int diff = dstY - srcY;
  404.         if (diff >= srcH) {
  405.         return;
  406.         }
  407.         srcOff += srcScan * diff;
  408.         srcY += diff;
  409.         srcH -= diff;
  410.     }
  411.     if (srcY + srcH > dstY + dstH) {
  412.         srcH = (dstY + dstH) - srcY;
  413.         if (srcH <= 0) {
  414.         return;
  415.         }
  416.     }
  417.     if (srcX < dstX) {
  418.         int diff = dstX - srcX;
  419.         if (diff >= srcW) {
  420.         return;
  421.         }
  422.         srcOff += diff;
  423.         srcX += diff;
  424.         srcW -= diff;
  425.     }
  426.     if (srcX + srcW > dstX + dstW) {
  427.         srcW = (dstX + dstW) - srcX;
  428.         if (srcW <= 0) {
  429.         return;
  430.         }
  431.     }
  432.     int dstPtr = dstOff + (srcY - dstY) * dstScan + (srcX - dstX);
  433.     if (intPixels == null) {
  434.         if (bytePixels == null) {
  435.         bytePixels = new byte[dstW * dstH];
  436.         dstScan = dstW;
  437.         dstOff = 0;
  438.         imageModel = model;
  439.         } else if (imageModel != model) {
  440.         convertToRGB();
  441.         }
  442.         if (bytePixels != null) {
  443.         for (int h = srcH; h > 0; h--) {
  444.             System.arraycopy(pixels, srcOff, bytePixels, dstPtr, srcW);
  445.             srcOff += srcScan;
  446.             dstPtr += dstScan;
  447.         }
  448.         }
  449.     }
  450.     if (intPixels != null) {
  451.         int dstRem = dstScan - srcW;
  452.         int srcRem = srcScan - srcW;
  453.         for (int h = srcH; h > 0; h--) {
  454.         for (int w = srcW; w > 0; w--) {
  455.             intPixels[dstPtr++] = model.getRGB(pixels[srcOff++]&0xff);
  456.         }
  457.         srcOff += srcRem;
  458.         dstPtr += dstRem;
  459.         }
  460.     }
  461.     flags |= ImageObserver.SOMEBITS;
  462.     }
  463.  
  464.     /**
  465.      * The setPixels method is part of the ImageConsumer API which
  466.      * this class must implement to retrieve the pixels.
  467.      */
  468.     public void setPixels(int srcX, int srcY, int srcW, int srcH,
  469.               ColorModel model,
  470.               int pixels[], int srcOff, int srcScan) {
  471.     if (srcY < dstY) {
  472.         int diff = dstY - srcY;
  473.         if (diff >= srcH) {
  474.         return;
  475.         }
  476.         srcOff += srcScan * diff;
  477.         srcY += diff;
  478.         srcH -= diff;
  479.     }
  480.     if (srcY + srcH > dstY + dstH) {
  481.         srcH = (dstY + dstH) - srcY;
  482.         if (srcH <= 0) {
  483.         return;
  484.         }
  485.     }
  486.     if (srcX < dstX) {
  487.         int diff = dstX - srcX;
  488.         if (diff >= srcW) {
  489.         return;
  490.         }
  491.         srcOff += diff;
  492.         srcX += diff;
  493.         srcW -= diff;
  494.     }
  495.     if (srcX + srcW > dstX + dstW) {
  496.         srcW = (dstX + dstW) - srcX;
  497.         if (srcW <= 0) {
  498.         return;
  499.         }
  500.     }
  501.     if (intPixels == null) {
  502.         if (bytePixels == null) {
  503.         intPixels = new int[dstW * dstH];
  504.         dstScan = dstW;
  505.         dstOff = 0;
  506.         imageModel = model;
  507.         } else {
  508.         convertToRGB();
  509.         }
  510.     }
  511.     int dstPtr = dstOff + (srcY - dstY) * dstScan + (srcX - dstX);
  512.     if (imageModel == model) {
  513.         for (int h = srcH; h > 0; h--) {
  514.         System.arraycopy(pixels, srcOff, intPixels, dstPtr, srcW);
  515.         srcOff += srcScan;
  516.         dstPtr += dstScan;
  517.         }
  518.     } else {
  519.         if (imageModel != ColorModel.getRGBdefault()) {
  520.         convertToRGB();
  521.         }
  522.         int dstRem = dstScan - srcW;
  523.         int srcRem = srcScan - srcW;
  524.         for (int h = srcH; h > 0; h--) {
  525.         for (int w = srcW; w > 0; w--) {
  526.             intPixels[dstPtr++] = model.getRGB(pixels[srcOff++]);
  527.         }
  528.         srcOff += srcRem;
  529.         dstPtr += dstRem;
  530.         }
  531.     }
  532.     flags |= ImageObserver.SOMEBITS;
  533.     }
  534.  
  535.     /**
  536.      * The imageComplete method is part of the ImageConsumer API which
  537.      * this class must implement to retrieve the pixels.
  538.      */
  539.     public synchronized void imageComplete(int status) {
  540.     grabbing = false;
  541.     switch (status) {
  542.     default:
  543.     case IMAGEERROR:
  544.         flags |= ImageObserver.ERROR | ImageObserver.ABORT;
  545.         break;
  546.     case IMAGEABORTED:
  547.         flags |= ImageObserver.ABORT;
  548.         break;
  549.     case STATICIMAGEDONE:
  550.         flags |= ImageObserver.ALLBITS;
  551.         break;
  552.     case SINGLEFRAMEDONE:
  553.         flags |= ImageObserver.FRAMEBITS;
  554.         break;
  555.     }
  556.     producer.removeConsumer(this);
  557.     notifyAll();
  558.     }
  559.  
  560.     /**
  561.      * DEPRECATED:  Replaced by getStatus().
  562.      */
  563.     public synchronized int status() {
  564.     return flags;
  565.     }
  566. }
  567.